#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;
using Weazel.Gezel.Model.Errors;

#endregion

namespace Weazel.Gezel.Parser
{
  public static class ParseModel
  {
    public static Model.Model Parse(ref List<ParseError> errors, string description)
    {
      return Parse(ref errors, description, "no file");
    }

    public static Model.Model Parse(ref List<ParseError> errors, string description, string filename)
    {
      Tokenizer t = new Tokenizer(description, filename);
      Model.Model model = Parse(new Set<Token>(Token.Eof), t);
      errors = t.Errors;
      return model;
    }

		public static void Parse(ref Model.Model model, ref List<ParseError> errors, string description)
		{
			Tokenizer t = new Tokenizer(description, "no file");
			Parse(ref model, new Set<Token>(Token.Eof), t);
			errors = t.Errors;
		}

    /// <summary>
    /// Utility method which is helpful if the
    /// caller just wants to construct a model 
    /// from a description quickly.
    /// </summary>
    /// <param name="description"></param>
    /// <returns></returns>
    public static Model.Model ParseAndVerify(string description)
    {
      List<ParseError> errors = new List<ParseError>();
			List<VerificationError> verificationErrors = new List<VerificationError>();
			List<VerificationWarning> warnings = new List<VerificationWarning>();

      Model.Model model = Parse(ref errors, description, "no file");

      // perform verification don't care about
      // results for now
			model.Verify(ref verificationErrors, ref warnings);
      return model;
    }

		public static Model.Model Parse(Set<Token> follow, Tokenizer t)
		{
			Weazel.Gezel.Model.Model model = new Weazel.Gezel.Model.Model("model");
			return Parse(ref model, follow, t);
		}

    public static Model.Model Parse(ref Model.Model model, Set<Token> follow, Tokenizer t)
    {      

      Set<Token> current = new Set<Token>(
        Token.Dp,
        Token.Hardwired,
        Token.Sequencer,
        Token.Fsm,
        Token.System,
        Token.Ipblock,
        Token.Constant,
        Token.OptionDirective
      );

      bool done = false;

      do
      {
        t.Check(follow.Union(current));

        if (t.CurrentToken == Token.Dp)
        {
          ParseDatapath.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.Hardwired)
        {
          ParseHardwired.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.Sequencer)
        {
          ParseSequencer.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.Fsm)
        {
          ParseFsm.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.System)
        {
          ParseSystem.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.Ipblock)
        {
          ParseIpBlock.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.Constant)
        {
          ParseConstant.Parse(follow.Union(current), t, model);
        }
        else if (t.CurrentToken == Token.OptionDirective)
        {
          ParseOptionDirective.Parse(follow.Union(current), t, model);
        }
        else
        {
          done = true;
        }

      } while (!done);

      return model;
    }
  }
}